package com.chinacoal.microservice.timedTasks;

import com.chinacoal.microservice.mapper.*;
import com.chinacoal.microservice.pojo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author zhuliang
 * @version V1.0
 * @Description: 定时任务类
 * @date 2020-11-27 14：38
 */
@Slf4j
@Component
public class GenerateExpenseInformationTask {

    @Autowired
    private CcmsSmartleasingExpenseManagMapper expenseManagMapper;

    @Autowired
    private CcmsSmartleasingContractMapper contractMapper;

    @Autowired
    private CcmsSmartleasingNoticeMapper noticeMapper;

    @Autowired
    private CcmsSmartleasingExpenseEntryMapper expenseEntryMapper;

    @Autowired
    private CcmsSmartleasingTenantMapper tenantMapper;

    @Autowired
    private CcmsSmartleasingRoomMapper roomMapper;

    @Autowired
    private CcmsSmartleasingHistoricalPaymentMapper historicalPaymentMapper;

    @Autowired
    private CcmsSmartleasingRegionalAnalysisMapper regionalAnalysisMapper;

    @Autowired
    private CcmsSmartleasingDeviceManagementMapper deviceManagementMapper;

    @Autowired
    private CcmsSmartleasingDeviceChangeMapper deviceChangeMapper;

    private List<String> entryPkIdList;

    private List<String> entryFkRoomIdList ;

    private  List<String> expenseManagePkIdList ;

    public GenerateExpenseInformationTask() {
         entryPkIdList= new ArrayList<>();
         entryFkRoomIdList = new ArrayList<>();
         expenseManagePkIdList = new ArrayList<>();
    }
    /**
     * @Description: 每月1号的0：30,开始创建费用信息,并将模板信息写入通知单中
     * @author zhuliang
     * @date 2020/11/27 16:12
     */
    @Scheduled(cron = "0 30 0 1 * ?")
    @Transactional
    public void generateExpenseInformation() {
        log.info("定时任务开启-->" + "每月1号的0：30,开始创建费用信息,并将模板信息写入通知单中");

        //查询所有生效的合同id
        List<CcmsSmartleasingContract> contractIdList = contractMapper.getAllIdByContractState();

        if (0 == contractIdList.size()) {
            log.info("定时任务结束-->" + "每月1号的0：30,开始创建费用信息,并将模板信息写入通知单中（没有需要创建的费用信息）");
            return;
        }

        //定义存放要添加的费用信息集合
        List<CcmsSmartleasingExpenseManag> expenseManagList = new ArrayList<>();

        //定义要生成的费用录入信息集合
        List<CcmsSmartleasingExpenseEntry> expenseEntryList = new ArrayList<>();

        //完善费用表信息，和费用录入表信息
        for (CcmsSmartleasingContract contractId : contractIdList) {
            CcmsSmartleasingExpenseManag expenseManag = new CcmsSmartleasingExpenseManag();
            expenseManag.setPkExpenseManagId(UUID.randomUUID() + "")
                    .setCreationDate(new Date())
                    .setLastUpdatedBy(0)
                    .setLastUpdateDate(new Date())
                    .setFkContractId(contractId.getPkContractId())
                    .setStatisticsMonth(new Date())
                    .setMeterReadingStatus("0")
                    .setExpensesReceivable(contractId.getMonthlyRent());
            expenseManagList.add(expenseManag);
            expenseManagePkIdList.add(expenseManag.getPkExpenseManagId());

            CcmsSmartleasingExpenseEntry expenseEntry = new CcmsSmartleasingExpenseEntry();
            expenseEntry.setCreationDate(new Date())
                    .setCreatedBy(0)
                    .setLastUpdateDate(new Date())
                    .setLastUpdatedBy(0)
                    .setFkRoomId(contractId.getFkRoomId())
                    .setPkExpenseEntryId(UUID.randomUUID() + "")
                    .setExpenseMonth(new Date())
                    .setFkExpenseManagId(expenseManag.getPkExpenseManagId());
            expenseEntryList.add(expenseEntry);

            entryPkIdList.add(expenseEntry.getPkExpenseEntryId());

            entryFkRoomIdList.add(expenseEntry.getFkRoomId());
        }

        //批量添加到数据库中
        expenseManagMapper.batchAdd(expenseManagList);
        expenseEntryMapper.batchAdd(expenseEntryList);

        //根据合同id查询信息
        List<CcmsSmartleasingNotice> notices = noticeMapper.getInformationByContractId();

        //完善信息
        for (CcmsSmartleasingNotice notice : notices) {
            notice.setPkNoticeId(UUID.randomUUID() + "")
                    .setCreatedBy(0)
                    .setCreationDate(new Date())
                    .setLastUpdatedBy(0)
                    .setLastUpdateDate(new Date())
                    .setExpenseMonth(new Date())
                    .setAddress(notice.getBuildingName()+ "-" + notice.getFloor() + "层-" + notice.getHouseNumber());
            //if (null != notice.getUnitPriceGarbageTreatment() && !notice.getUnitPriceGarbageTreatment().equals(BigDecimal.ZERO) && null != notice.getGarbageTreatmentMagnification() && !notice.getGarbageTreatmentMagnification().equals(BigDecimal.ZERO)) {
            //    notice.setTrashHandlingFee(notice.getUnitPriceGarbageTreatment().multiply(notice.getGarbageTreatmentMagnification()).setScale(2,BigDecimal.ROUND_HALF_UP));
            //}
            Calendar c1 = Calendar.getInstance();
            Calendar c2 = Calendar.getInstance();
            c1.setTime(notice.getExpenseMonth());
            c2.setTime(notice.getContractEndTime());
            if ((c2.get(Calendar.YEAR) == c1.get(Calendar.YEAR)) && (c2.get(Calendar.MONTH) == c1.get(Calendar.MONTH))) {
                    if (notice.getDeposit().compareTo(notice.getMonthlyRent())>=0)
                        //押金大于等于月租，则置0
                        notice.setMonthlyRent(BigDecimal.ZERO);
            };

            // totalAmount和ER 这2个字段需要初始化，否则列表显示错误
            notice.setTotalAmount(notice.getMonthlyRent());
            notice.setExpensesReceivable(notice.getMonthlyRent());

            if (null != notice.getUnitPriceElevatorFee() && !notice.getUnitPriceElevatorFee().equals(BigDecimal.ZERO) && null != notice.getConstructionArea() && !notice.getConstructionArea().equals(BigDecimal.ZERO)) {
                notice.setElevatorRate(notice.getUnitPriceElevatorFee().multiply(notice.getConstructionArea()).setScale(2,BigDecimal.ROUND_HALF_UP));
            }
        }

        //批量添加到数据库中
        noticeMapper.batchAdd(notices);

        log.info("定时任务结束-->" + "每月1号的0：30,开始创建费用信息,并将模板信息写入通知单中");
    }

    /**
     * @Description: 每月1号凌晨0：15查询上个月未缴费的，租户信息改为欠费
     * @author zhuliang
     * @date 2020/12/10 16:43
     */
    @Scheduled(cron = "0 15 0 1 * ?")
    public void updatePaymentStatus() {
        log.info("定时任务开启-->" + "每月1号凌晨0：15查询上个月未缴费的，租户信息改为欠费");

        //查询所有未缴费的租户id
        List<String> ids = expenseManagMapper.getAllTenantIdByPay();

        //批量修改租户的缴费状态
        tenantMapper.batchUpdate(new Date(), 0, "1", ids);

        log.info("定时任务结束-->" + "每月1号凌晨0：15查询上个月未缴费的，租户信息改为欠费");
    }

    /**
     * @Description: 每天凌晨0：10查询所有合同到期的合同信息和合同生效期到的合同,并修改合同状态
     * @author zhuliang
     * @date 2020/11/25 10:11
     */
    @Transactional
    @Scheduled(cron = "0 10 0 * * ?")
    public void contractExpires() {
        log.info("定时任务开启-->" + "每天凌晨0：10查询所有合同到期的合同信息和合同生效期到的合同,并修改合同状态");

        //查询所有超过和他时间的合同信息
        List<CcmsSmartleasingContract> countByDate = contractMapper.getCountByDate(new Date());

        //修改合同状态,和房间状态
        for (CcmsSmartleasingContract contract : countByDate) {
            contract.setContractState(new Byte("2"))
                    .setLastUpdateDate(new Date())
                    .setLastUpdatedBy(0)
                    .setContractActualEndTime(new Date())
                    .setRefundInstructions("合同已经到期");
            contractMapper.updateById(contract);

            CcmsSmartleasingRoom room = new CcmsSmartleasingRoom();
            room.setPkRoomId(contract.getFkRoomId())
                    .setLastUpdatedBy(0)
                    .setLastUpdateDate(new Date())
                    .setFkRoomStatusId("ca68415c-1df1-11eb-9143-00ffb95445a5");
            roomMapper.updateById(room);
        }

        //查询所有已审核待生效的合同信息
        List<CcmsSmartleasingContract> effectiveContract = contractMapper.getEffectiveContract();

        for (CcmsSmartleasingContract smartleasingContract : effectiveContract) {
            smartleasingContract.setLastUpdatedBy(0).setLastUpdateDate(new Date()).setContractState(new Byte("1"));
            contractMapper.updateById(smartleasingContract);

            CcmsSmartleasingTenant tenant = tenantMapper.selectById(smartleasingContract.getFkTenantId());
            tenant.setTenantStatus(new Byte("1"));
            tenant.setLastUpdatedBy(0);
            tenant.setLastUpdateDate(new Date());
            tenantMapper.updateById(tenant);

            roomMapper.updateStatusBySurrender(new Date(), 0, "bbf1d3f0-1df1-11eb-9143-00ffb95445a5", smartleasingContract.getFkRoomId());
        }

        log.info("定时任务结束-->" + "每天凌晨0：10查询所有合同到期的合同信息和合同生效期到的合同,并修改合同状态");
    }

    /**
     * @Description: 每月1号0:20生成上一个月数据中心数据
     * @author zhuliang
     * @date 2020/12/30 17:56
     */
    @Scheduled(cron = "0 20 0 1 * ?")
    @Transactional
    public void generateDataCenterData() {
        log.info("定时任务开启-->" + "每月1号0:20生成上一个月数据中心数据");

        //得到区域分析所需要的数据
        List<CcmsSmartleasingRegionalAnalysis> regionalAnalyses = regionalAnalysisMapper.getRecordInformation();

        //得到上个月的时间
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.MONTH, -1);
        Date time = c.getTime();

        //完善信息
        for (CcmsSmartleasingRegionalAnalysis regionalAnalysis : regionalAnalyses) {
            int rate = 0;
            if (null != regionalAnalysis.getNumberOfRentals() && 0 != regionalAnalysis.getNumberOfRentals() && null != regionalAnalysis.getTotalNumberOfRooms() && 0 != regionalAnalysis.getTotalNumberOfRooms()) {
                rate = (int) Math.round(regionalAnalysis.getNumberOfRentals() * 1.0 / regionalAnalysis.getTotalNumberOfRooms() * 100);
            }

            regionalAnalysis.setPkRegionalAnalysisId(UUID.randomUUID() + "")
                    .setCreatedBy(0)
                    .setCreationDate(new Date())
                    .setLastUpdatedBy(0)
                    .setLastUpdateDate(new Date())
                    .setCollectionMonth(time)
                    .setOccupancyRate(rate);
        }

        //批量添加
        regionalAnalysisMapper.bathAdd(regionalAnalyses);

        //查询本月所有收款金额
        BigDecimal total = historicalPaymentMapper.getTotal();

        //生成本月综合分析数据
        CcmsSmartleasingHistoricalPayment historicalPayment = new CcmsSmartleasingHistoricalPayment();
        historicalPayment.setPkHistoricalPaymentId(UUID.randomUUID() + "")
                .setCreatedBy(0)
                .setCreationDate(new Date())
                .setLastUpdatedBy(0)
                .setLastUpdateDate(new Date())
                .setCollectionMonth(time)
                .setAmountCollected(total);
        historicalPaymentMapper.insert(historicalPayment);

        log.info("定时任务结束-->" + "每月1号0:20生成上一个月数据中心数据");
    }

    /**
     * @Description: 每月1号的0：50,开始自动抄表
     * @author liule
     * @date 2022年11月24日 09:13:10
     */
    @Scheduled(cron = "0 50 0 1 * ?")
    @Transactional
    public void updateEntriesInformation() {
        BigDecimal lastMonthWaterMobility;
        BigDecimal thisMonthWaterMobility = null;
        BigDecimal thisMonthWaterConsumption = null;

        BigDecimal lastMonthHotWaterMobility;
        BigDecimal thisMonthHotWaterMobility = null;
        BigDecimal thisMonthHotWaterConsumption = null;

        BigDecimal lastMonthElectricMobility;
        BigDecimal thisMonthElectricMobility = null;
        BigDecimal thisMonthElectricConsumption = null;

        CcmsSmartleasingExpenseEntry eeLastMonth ;
        CcmsSmartleasingExpenseEntry eeThisMonth = new CcmsSmartleasingExpenseEntry();
        CcmsSmartleasingExpenseManag em = new CcmsSmartleasingExpenseManag();

        List<CcmsSmartleasingDeviceManagement> lstDM;
        Integer i=0;
        String roomId,expenseManagId;
        BigDecimal deviceReadings;

        log.info("定时任务开启-->" + "每月1号的0：50,开始抄表");
        for (String entryPkId:entryPkIdList) {
            roomId = entryFkRoomIdList.get(i);
            if (roomId == null || roomId.isEmpty())
                break;
            eeLastMonth = expenseEntryMapper.getLastMonthMobilityByRoomId(roomId);
            if (eeLastMonth == null) {
                lastMonthWaterMobility = null;
                lastMonthElectricMobility = null;
                lastMonthHotWaterMobility = null;
            }
            else {
                lastMonthWaterMobility = eeLastMonth.getMonthWaterMobility();
                lastMonthElectricMobility = eeLastMonth.getMonthElectricityMobility();
                lastMonthHotWaterMobility = eeLastMonth.getMonthHotWaterMobility();
            }

            lstDM = deviceManagementMapper.getThisMonthMobilityByRoom(roomId);
            if (lstDM == null) {
                thisMonthWaterMobility = null;
                thisMonthHotWaterMobility = null;
                thisMonthElectricMobility = null;
            }
            else {
                for (CcmsSmartleasingDeviceManagement dm:lstDM) {
                    deviceReadings = dm.getDeviceReadings();
                    if (deviceReadings == null)
                        deviceReadings = null;

                    if (dm.getFkEquipmentTypeId().compareTo( "yunding.electric_meter") == 0)
                        thisMonthElectricMobility = deviceReadings;
                    else { //only water and hot water since the above query criteria limit only electric, water, and hot water
                        if (dm.getFkEquipmentTypeId().compareTo( "yunding.water_meter") == 0)
                            thisMonthWaterMobility = deviceReadings;
                        else if (dm.getFkEquipmentTypeId().compareTo("yunding.hot_water_meter") == 0)
                            thisMonthHotWaterMobility = deviceReadings;
                    }
                }
            }

            //计算用量区分2种情况
            // 1.上月无换表：则总用量 = 本月行度-上月行度；
            // 2.上月有换表：则总用量= （上月内第一次换表时的老表行度-上月行度）+（sum(每次换表时用量））+（本月行度-上月最后一次换表时的新表行度）

            List<CcmsSmartleasingDeviceChange> lstDeviceChange = deviceChangeMapper.getAllByConditionLastMonth(roomId);
            Integer iListSize = lstDeviceChange.size();
            if (iListSize == 0) {
                if (thisMonthWaterMobility == null || lastMonthWaterMobility == null)
                    thisMonthWaterConsumption = null;
                else
                    thisMonthWaterConsumption = thisMonthWaterMobility.subtract(lastMonthWaterMobility);

                if (thisMonthHotWaterMobility == null || lastMonthHotWaterMobility == null)
                    thisMonthHotWaterConsumption = null;
                else
                    thisMonthHotWaterConsumption = thisMonthHotWaterMobility.subtract(lastMonthHotWaterMobility);

                if (thisMonthElectricMobility == null || lastMonthElectricMobility == null)
                    thisMonthElectricConsumption = null;
                else
                    thisMonthElectricConsumption = thisMonthElectricMobility.subtract(lastMonthElectricMobility);
            } else {
                BigDecimal bdOldWaterReadingAtFirstChangeLastMonth = null,bdOldHotWaterReadingAtFirstChangeLastMonth = null;
                BigDecimal bdOldElectricReadingAtFirstChangeLastMonth = null;
                BigDecimal bdNewWaterReadingAtLastChangeLastMonth = null,bdNewHotWaterReadingAtLastChangeLastMonth = null;
                BigDecimal bdNewElectricReadingAtLastChangeLastMonth = null;
                BigDecimal bdWaterConsumptionTotalLastMonth = null, bdHotWaterConsumptionTotalLastMonth = null;
                BigDecimal bdElectricConsumptionTotalLastMonth = null;
                BigDecimal bdWaterConsumptionInDC = null, bdHotWaterConsumptionInDC = null, bdElectricConsumptionInDC = null;

                Integer iDC = 0;
                for (CcmsSmartleasingDeviceChange dc:lstDeviceChange) {
                    iDC++;
                    if (iDC == 1) {
                       bdOldWaterReadingAtFirstChangeLastMonth =dc.getOldWaterReading();
                       bdOldHotWaterReadingAtFirstChangeLastMonth = dc.getOldHotWaterReading();
                       bdOldElectricReadingAtFirstChangeLastMonth = dc.getOldElectricReading();
                    }
                    else if (iDC == iListSize) {
                        bdNewWaterReadingAtLastChangeLastMonth = dc.getNewWaterReading();
                        bdNewHotWaterReadingAtLastChangeLastMonth = dc.getNewHotWaterReading();
                        bdNewElectricReadingAtLastChangeLastMonth = dc.getNewElectricReading();
                    }

                    bdWaterConsumptionInDC = dc.getOldWaterConsumption();
                    bdHotWaterConsumptionInDC = dc.getOldHotWaterConsumption();
                    bdElectricConsumptionInDC = dc.getOldElectricConsumption();

                    if (bdWaterConsumptionInDC != null) {
                        if (bdWaterConsumptionTotalLastMonth == null)
                            bdWaterConsumptionTotalLastMonth = BigDecimal.ZERO;
                        bdWaterConsumptionTotalLastMonth = bdWaterConsumptionTotalLastMonth.add(bdWaterConsumptionInDC);
                    }

                    if (bdHotWaterConsumptionInDC != null) {
                        if (bdHotWaterConsumptionTotalLastMonth == null)
                            bdHotWaterConsumptionTotalLastMonth = BigDecimal.ZERO;
                        bdHotWaterConsumptionTotalLastMonth = bdHotWaterConsumptionTotalLastMonth.add(bdHotWaterConsumptionInDC);
                    }

                    if (bdElectricConsumptionInDC != null) {
                        if (bdElectricConsumptionTotalLastMonth == null)
                            bdElectricConsumptionTotalLastMonth = BigDecimal.ZERO;
                        bdElectricConsumptionTotalLastMonth = bdElectricConsumptionTotalLastMonth.add(bdElectricConsumptionInDC);
                    }
                } // at the end we get total consumption for last month, and 1st/last reading for each meter in this room

                if (bdOldWaterReadingAtFirstChangeLastMonth != null && lastMonthWaterMobility != null) {
                    thisMonthWaterConsumption = bdOldWaterReadingAtFirstChangeLastMonth.subtract(lastMonthWaterMobility);

                    if (bdWaterConsumptionTotalLastMonth != null) {
                        thisMonthWaterConsumption = thisMonthWaterConsumption.add(bdWaterConsumptionTotalLastMonth);

                        if (bdNewWaterReadingAtLastChangeLastMonth != null && thisMonthWaterMobility != null)
                            thisMonthWaterConsumption = thisMonthWaterConsumption.add(thisMonthWaterMobility.subtract(bdNewWaterReadingAtLastChangeLastMonth));
                    }
                }

                if (bdOldHotWaterReadingAtFirstChangeLastMonth != null && lastMonthHotWaterMobility != null) {
                    thisMonthHotWaterConsumption = bdOldHotWaterReadingAtFirstChangeLastMonth.subtract(lastMonthHotWaterMobility);

                    if (bdHotWaterConsumptionTotalLastMonth != null) {
                        thisMonthHotWaterConsumption = thisMonthHotWaterConsumption.add(bdHotWaterConsumptionTotalLastMonth);

                        if (bdNewHotWaterReadingAtLastChangeLastMonth != null && thisMonthHotWaterMobility != null)
                            thisMonthHotWaterConsumption = thisMonthHotWaterConsumption.add(thisMonthHotWaterMobility.subtract(bdNewHotWaterReadingAtLastChangeLastMonth));
                    }
                }

                if (bdOldElectricReadingAtFirstChangeLastMonth != null && lastMonthElectricMobility != null) {
                    thisMonthElectricConsumption = bdOldElectricReadingAtFirstChangeLastMonth.subtract(lastMonthElectricMobility);

                    if (bdElectricConsumptionTotalLastMonth != null) {
                        thisMonthElectricConsumption = thisMonthElectricConsumption.add(bdElectricConsumptionTotalLastMonth);

                        if (bdNewElectricReadingAtLastChangeLastMonth != null && thisMonthElectricMobility != null)
                            thisMonthElectricConsumption = thisMonthElectricConsumption.add(thisMonthElectricMobility.subtract(bdNewElectricReadingAtLastChangeLastMonth));
                    }
                }

            }

            eeThisMonth.setPkExpenseEntryId(entryPkId);
            eeThisMonth.setMonthWaterMobility(thisMonthWaterMobility);
            eeThisMonth.setMonthHotWaterMobility(thisMonthHotWaterMobility);
            eeThisMonth.setMonthElectricityMobility(thisMonthElectricMobility);
            eeThisMonth.setLastMonthWaterMobility(lastMonthWaterMobility);
            eeThisMonth.setLastMonthHotWaterMobility(lastMonthHotWaterMobility);
            eeThisMonth.setLastMonthElectricityMobility(lastMonthElectricMobility);
            eeThisMonth.setMonthWaterConsumption(thisMonthWaterConsumption);
            eeThisMonth.setMonthHotWaterConsumption(thisMonthHotWaterConsumption);
            eeThisMonth.setMonthElectricityConsumption(thisMonthElectricConsumption);

            expenseEntryMapper.updateThisMonthEntryDataByPkId(eeThisMonth);

            if (thisMonthWaterConsumption != null && thisMonthHotWaterConsumption != null && thisMonthElectricConsumption != null) {
                expenseManagId = expenseManagePkIdList.get(i);
                em.setPkExpenseManagId(expenseManagId);
                em.setMeterReadingStatus("1");
                em.setMeterReadingTime(new Date());
                expenseManagMapper.updateById(em);
            }
            i = i+1;
        }

        log.info("定时任务结束-->" + "每月1号的0：50,开始抄表");
    }
}
